package jdk.collection.custom;

import lombok.Data;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 一个基本操作为add,entrySet的Map实现，主要应用在返回数据方面。
 * @param <K>
 * @param <V>
 */
public class ArrayMap<K, V> implements Map<K, V> {

    //TODO 这个modCount机制不完善。
    transient int modCount = 0;
    transient List<Element> array = new ArrayList();
    transient Set<Map.Entry<K, V>> entrySet;

    @Override
    public int size() {
        return array.size();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return false;
    }

    @Override
    public boolean containsValue(Object value) {
        return false;
    }

    @Override
    public V get(Object key) {
        if(key==null)
            throw new NullPointerException("键不能空");
        Element element = getElementByKey(key);
        if(element!=null)
            return element.getValue();
        return null;
    }

    private Element getElementByKey(Object key){
        for(Element element : array){
            if(element.getKey().equals(key))
                return element;
        }
        return null;
    }

    @Override
    public V put(K key, V value) {
        if(key==null)
            throw new NullPointerException("键不能空");
        Element element = getElementByKey(key);
        if(element!=null){
            V oldValue = element.getValue();
            element.setValue(value);
            return oldValue;
        }
        Element newElement = new Element(key, value);
        array.add(newElement);
        return null;
    }

    @Override
    public V remove(Object key) {
        if(key==null)
            throw new NullPointerException("键不能空");
        Element element = getElementByKey(key);
        if(element!=null){
            array.remove(element);
            return element.getValue();
        }
        return null;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        array.clear();
    }

    @Override
    public Set<K> keySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<V> values() {
        throw new UnsupportedOperationException();
    }

    class Element implements Map.Entry<K, V>{
        private K key;
        private V value;

        public Element(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(V value) {
            return this.value = value;
        }
    }




    @Override
    public Set<Entry<K, V>> entrySet() {
        Set<Entry<K, V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }

    final class EntrySet extends AbstractSet<Entry<K, V>>{

        @Override
        public Iterator<Entry<K, V>> iterator() {
            return new EntryIterator();
        }

        @Override
        public int size() {
            return array.size();
        }
    }


    final class EntryIterator implements Iterator<Map.Entry<K,V>>{

        int cursorIndex = 0;

        @Override
        public boolean hasNext() {
            return cursorIndex<=size()-1;
        }

        @Override
        public Entry<K, V> next() {
            Element element = array.get(cursorIndex++);
            return element;
        }
    }


    public synchronized String toString() {
        int max = size() - 1;
        if (max == -1)
            return "{}";

        StringBuilder sb = new StringBuilder();
        Iterator<Map.Entry<K,V>> it = entrySet().iterator();

        sb.append('{');
        for (int i = 0; ; i++) {
            Map.Entry<K,V> e = it.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key.toString());
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value.toString());

            if (i == max)
                return sb.append('}').toString();
            sb.append(", ");
        }
    }
}
